#include <climits>
#include <ostream>
#include <string.h>
#include <iostream>

using std::cout;
using std::endl;

class String
{
public:
    String();
    String(const char *pstr);
    String(const String &rhs);
    String &operator=(const String &rhs);

    //下标访问运算符的重载
    /* char &operator[](size_t idx); */
private:
    class CharProxy
    {
    public:
        CharProxy(String &self, size_t idx);
        char &operator=(const char &ch);
        /* friend std::ostream &operator<<(std::ostream &os, const CharProxy &rhs); */
        //类型转换函数
        operator char()
        {
            cout << "operator char()" <<endl;
            return _self._pstr[_idx];
        }
    private:
        String &_self;
        size_t _idx;

    };
public:
    CharProxy operator[](size_t idx);

    //获取字符串的长度
    size_t size() const;

    //获取底层字符串
    const char *c_str() const;

    //获取引用计数
    int getRefCount() const;

    ~String();

private:
    //初始化引用计数
    void initRefCount();

    //引用计数++
    void increRefCount();

    //引用计数--
    void decreRefCount();

    //释放操作
    void release();

    friend std::ostream &operator<<(std::ostream &os, const String &rhs);
    /* friend std::ostream &operator<<(std::ostream &os, const String::CharProxy &rhs); */
private:
    char *_pstr;
};

std::ostream &operator<<(std::ostream &os, const String &rhs)
{
    if(rhs._pstr)
    {
        os << rhs._pstr;
    }
    return os;
}

String::String()
: _pstr(new char[5]() + 4)
{
    cout << "String()" << endl;
    initRefCount();
}

String::String(const char *pstr)
: _pstr(new char[strlen(pstr) + 5]() + 4)
{
    cout <<"String(const char *)" << endl;
    strcpy(_pstr, pstr);
    initRefCount();
}

String::String(const String &rhs)
: _pstr(rhs._pstr)
{
    cout << "String(const String &)" << endl;
    increRefCount();
}

String &String::operator=(const String &rhs)
{
    cout << "String &operator=(const String &)" << endl;
    if(this != &rhs)//1、自赋值
    {
        //2、释放左操作数
        release();

        //3、浅拷贝
        _pstr = rhs._pstr;
        increRefCount();
    }

    return *this;//4、返回*this
}

String::CharProxy::CharProxy(String &self, size_t idx)
: _self(self)
, _idx(idx)
{

}

//CharProxy = char
char &String::CharProxy::operator=(const char &ch)
{
    if(_idx < _self.size())
    {
        //是不是共享的
        if(_self.getRefCount() > 1)
        {
            char *ptmp = new char[_self.size() + 5]() + 4;//1、申请空间
            strcpy(ptmp, _self._pstr);//2、拷贝操作
            _self.decreRefCount();//3、引用计数-1
            _self._pstr = ptmp;//4、指针改变指向 
            _self.initRefCount();//5、初始化引用计数
        }
         _self._pstr[_idx] = ch;//赋值
        return _self._pstr[_idx];
    }
    else
    {
        static char nullChar = '\0';
        return nullChar;
    }

}
#if 0
std::ostream &operator<<(std::ostream &os, const String::CharProxy &rhs)
{
    os << rhs._self._pstr[rhs._idx];

    return os;
}
#endif
#if 0
//s3[0] = 'H';//写时才需要进行赋值，深拷贝
char &String::operator[](size_t idx)
{
    if(idx < size())
    {
        //是不是共享的
        if(getRefCount() > 1)
        {
            char *ptmp = new char[this->size() + 5]() + 4;//1、申请空间
            strcpy(ptmp, _pstr);//2、拷贝操作
            decreRefCount();//3、引用计数-1
            _pstr = ptmp;//4、指针改变指向 
            initRefCount();//5、初始化引用计数
        }
        return _pstr[idx];
    }
    else
    {
        static char nullChar = '\0';
        return nullChar;
    }
}
#endif

String::CharProxy String::operator[](size_t idx)
{
    return CharProxy(*this, idx);
}

//获取字符串的长度
size_t String::size() const
{
    return strlen(_pstr);
}

//获取底层字符串
const char *String::c_str() const
{
    return _pstr;
}

int String::getRefCount() const
{
    return *(int *)(_pstr - 4);
}

String::~String()
{
    cout << "~String()" << endl;
    release();
}

void String::initRefCount()
{
    *(int *)(_pstr - 4) = 1;
}

void String::increRefCount()
{
    ++*(int *)(_pstr - 4);
}

void String::decreRefCount()
{
    --*(int *)(_pstr - 4);
}

void String::release()
{
    decreRefCount();
    if(0 == getRefCount())
    {
        delete [] (_pstr - 4);
    }
}

void test()
{
    String s1("hello");
    cout << "s1 = " << s1 << endl;
    cout << "s1.getRefCount() = " << s1.getRefCount() << endl;
    printf("&s1 = %p\n", s1.c_str());

    cout << endl;
    String s2 = s1;
    cout << "s1 = " << s1 << endl;
    cout << "s2 = " << s2 << endl;
    cout << "s1.getRefCount() = " << s1.getRefCount() << endl;
    cout << "s2.getRefCount() = " << s2.getRefCount() << endl;
    printf("&s1 = %p\n", s1.c_str());
    printf("&s2 = %p\n", s2.c_str());

    cout << endl;
    String s3("wangdao");
    cout << "s3 = " << s3 << endl;
    cout << "s3.getRefCount() = " << s3.getRefCount() << endl;
    printf("&s3 = %p\n", s3.c_str());

    cout << endl << "执行s3 = s1" << endl;
    s3 = s1;
    cout << "s1 = " << s1 << endl;
    cout << "s2 = " << s2 << endl;
    cout << "s3 = " << s3 << endl;
    cout << "s1.getRefCount() = " << s1.getRefCount() << endl;
    cout << "s2.getRefCount() = " << s2.getRefCount() << endl;
    cout << "s3.getRefCount() = " << s3.getRefCount() << endl;
    printf("&s1 = %p\n", s1.c_str());
    printf("&s2 = %p\n", s2.c_str());
    printf("&s3 = %p\n", s3.c_str());

    cout << endl << "对s3[0]执行写操作" << endl;
    s3[0] = 'H';//CharProxy = char char = char
    cout << "s1 = " << s1 << endl;
    cout << "s2 = " << s2 << endl;
    cout << "s3 = " << s3 << endl;
    cout << "s1.getRefCount() = " << s1.getRefCount() << endl;
    cout << "s2.getRefCount() = " << s2.getRefCount() << endl;
    cout << "s3.getRefCount() = " << s3.getRefCount() << endl;
    printf("&s1 = %p\n", s1.c_str());
    printf("&s2 = %p\n", s2.c_str());
    printf("&s3 = %p\n", s3.c_str());

    cout << endl << "对s1[0]执行读操作" << endl;
    //cout << CharProxy--->char
    //operator char
    cout << "s1[0] = " << s1[0] << endl;//cout << CharProxy
    cout << "s1 = " << s1 << endl;
    cout << "s2 = " << s2 << endl;
    cout << "s3 = " << s3 << endl;
    cout << "s1.getRefCount() = " << s1.getRefCount() << endl;
    cout << "s2.getRefCount() = " << s2.getRefCount() << endl;
    cout << "s3.getRefCount() = " << s3.getRefCount() << endl;
    printf("&s1 = %p\n", s1.c_str());
    printf("&s2 = %p\n", s2.c_str());
    printf("&s3 = %p\n", s3.c_str());
    //如何区分读与写？
    cout << endl << "对s1[0]执行xie操作" << endl;
    s1[0] = 'h';
    cout << "s1 = " << s1 << endl;
    cout << "s2 = " << s2 << endl;
    cout << "s3 = " << s3 << endl;
    cout << "s1.getRefCount() = " << s1.getRefCount() << endl;
    cout << "s2.getRefCount() = " << s2.getRefCount() << endl;
    cout << "s3.getRefCount() = " << s3.getRefCount() << endl;
    printf("&s1 = %p\n", s1.c_str());
    printf("&s2 = %p\n", s2.c_str());
    printf("&s3 = %p\n", s3.c_str());
}

int main(int argc, char *argv[])
{
    test();
    return 0;
}

